1 module spec; 2 import defs; 3 import util; 4 5 enum IndexFile = "api/gl.xml"; 6 enum PrependXMLFileLocation = "api/"; 7 8 void readInFunctionFamilies(ref OGLEnumGroup[] enums, ref OGLFunctionFamily[] families) { 9 import std.file : readText; 10 import std.experimental.xml; 11 12 string raw_input = readText(IndexFile); 13 14 auto domBuilder = raw_input 15 .lexer 16 .parser 17 .cursor((CursorError err){}) 18 .domBuilder; 19 domBuilder.setSource(raw_input); 20 domBuilder.buildRecursive; 21 auto dom = domBuilder.getDocument; 22 23 auto rootNode = dom.firstChild; 24 25 handleChildren(rootNode, enums, families); 26 27 debug(OGL_Spec) { 28 import std.stdio; 29 foreach(ref e; enums) { 30 writeln("- ", e.name, e.isBitmask ? " [bitmask]": ""); 31 foreach(ref e2; e.enums) { 32 if (e2.value !is null) 33 writeln(" - ", e2.name, " = ", e2.value); 34 } 35 } 36 } 37 } 38 39 void handleChildren(T)(ref T rootNode, ref OGLEnumGroup[] enums, ref OGLFunctionFamily[] ret_Functions) { 40 size_t emptyEnumGroup = -1; 41 foreach(i, ref e; enums) { 42 if (e.name is null) 43 emptyEnumGroup = i; 44 } 45 if (emptyEnumGroup == -1) { 46 emptyEnumGroup = enums.length; 47 enums ~= OGLEnumGroup(); 48 } 49 50 size_t emptyFunctionFamily = -1; 51 foreach(i, ref fg; ret_Functions) { 52 if (fg.familyOfFunction is null) 53 emptyFunctionFamily = i; 54 } 55 if (emptyFunctionFamily == -1) { 56 emptyFunctionFamily = ret_Functions.length; 57 ret_Functions ~= OGLFunctionFamily(); 58 } 59 60 F1: foreach(child; rootNode.childNodes) { 61 // Structure: 62 // - comment 63 // - types 64 // - groups (enums) 65 // - enums (value) 66 // - commands 67 // - feature 68 // - extensions 69 70 switch(child.nodeName) { 71 case "comment": 72 break; 73 case "groups": 74 F2: foreach(group; child.childNodes) { 75 string name = group.attributes.getNamedItem("name").nodeValue; 76 F3: foreach(ref eg; enums) { 77 if (eg.name == name) { 78 F4: foreach(child2; group.childNodes) { 79 if (child2.nodeName == "enum") { 80 string name2 = child2.attributes.getNamedItem("name").nodeValue; 81 foreach(ref e; eg.enums) { 82 if (e.name == name2) { 83 continue F4; 84 } 85 } 86 87 eg.enums ~= OGLEnum(name2); 88 continue F4; 89 } 90 } 91 92 continue F2; 93 } 94 } 95 96 enums ~= OGLEnumGroup(name); 97 goto F3; 98 } 99 continue F1; 100 101 case "enums": 102 string groupName, groupType; 103 104 if (child.attributes.getNamedItem("namespace").nodeValue == "OcclusionQueryEventMaskAMD") { 105 groupName = "OcclusionQueryEventMaskAMD"; 106 groupType = "bitmask"; 107 } else if (child.attributes.getNamedItem("group") !is null) { 108 groupName = child.attributes.getNamedItem("group").nodeValue; 109 if (child.attributes.getNamedItem("type") !is null) 110 groupType = child.attributes.getNamedItem("type").nodeValue; 111 } 112 113 OGLEnumGroup* group; 114 foreach(ref eg; enums) { 115 if (eg.name == groupName) { 116 group = ⪚ 117 break; 118 } 119 } 120 121 // no matter what we want to fill out all enums created 122 F6: foreach(child2; child.childNodes) { 123 if (child2.nodeName == "enum") { 124 string name = child2.attributes.getNamedItem("name").nodeValue; 125 string value = child2.attributes.getNamedItem("value").nodeValue; 126 127 bool wasSet; 128 foreach(ref group2; enums) { 129 foreach(ref e; group2.enums) { 130 if (e.name == name) { 131 e.value = value; 132 wasSet = true; 133 } 134 } 135 } 136 if (wasSet) 137 continue F6; 138 139 enums[emptyEnumGroup].enums ~= OGLEnum(name, value); 140 continue F6; 141 } 142 } 143 144 if (group !is null) 145 group.isBitmask = groupType == "bitmask"; 146 break; 147 148 case "commands": 149 F7: foreach(child2; child.childNodes) { 150 if (child2.nodeName == "command") { 151 string returnType, name; 152 string[] argTypes, argNames; 153 size_t argI; 154 155 argTypes.length = child2.childNodes.length-1; 156 argNames.length = child2.childNodes.length-1; 157 158 foreach(child3; child2.childNodes) { 159 switch(child3.nodeName) { 160 case "proto": 161 size_t i; 162 foreach(child4; child3.childNodes) { 163 if (child4.nodeName == "name") 164 break; 165 166 if (i > 0) 167 returnType ~= " "; 168 169 if (child4.nodeValue !is null) { 170 returnType ~= child4.nodeValue.fixTypePointer; 171 } 172 173 if (child4.childNodes.length > 0) { 174 returnType ~= child4.firstChild.nodeValue.fixTypePointer; 175 } 176 177 i++; 178 } 179 180 returnType = returnType.fixTypePointer; 181 182 name = child3.lastChild.firstChild.nodeValue; 183 break; 184 case "param": 185 size_t i; 186 foreach(child4; child3.childNodes) { 187 if (child4.nodeName == "name") 188 break; 189 190 if (i > 0) 191 argTypes[argI] ~= " "; 192 193 if (child4.nodeValue !is null) { 194 argTypes[argI] ~= child4.nodeValue.fixTypePointer; 195 } 196 197 if (child4.childNodes.length > 0) { 198 argTypes[argI] ~= child4.firstChild.nodeValue.fixTypePointer; 199 } 200 201 i++; 202 } 203 204 argTypes[argI] = argTypes[argI].fixTypePointer; 205 206 foreach(child4; child3.childNodes) { 207 if (child4.nodeName == "name") { 208 argNames[argI] = child4.firstChild.nodeValue; 209 break; 210 } 211 } 212 argI++; 213 break; 214 default: 215 argTypes.length--; 216 argNames.length--; 217 break; 218 } 219 } 220 221 foreach(ref fg; ret_Functions) { 222 foreach(ref fe; fg.functions) { 223 if (fe.name == name) { 224 continue F7; 225 } 226 } 227 } 228 229 ret_Functions[emptyFunctionFamily].functions ~= OGLFunction(returnType, name, argTypes, argNames); 230 } 231 } 232 break; 233 234 case "feature": 235 if (child.attributes.getNamedItem("api").nodeValue == "gl") { 236 string introducedInS = child.attributes.getNamedItem("number").nodeValue; 237 238 foreach(child2; child.childNodes) { 239 F8: foreach(child3; child2.childNodes) { 240 if (child3.nodeName == "command") { 241 string name = child3.attributes.getNamedItem("name").nodeValue; 242 243 foreach(ref fg; ret_Functions) { 244 foreach(ref fe; fg.functions) { 245 if (fe.name == name && fe.introducedIn == OGLIntroducedIn.Unknown) { 246 switch(introducedInS) { 247 case "1.0": fe.introducedIn = OGLIntroducedIn.V1P0; break; 248 case "1.1": fe.introducedIn = OGLIntroducedIn.V1P1; break; 249 case "1.2": fe.introducedIn = OGLIntroducedIn.V1P2; break; 250 case "1.3": fe.introducedIn = OGLIntroducedIn.V1P3; break; 251 case "1.4": fe.introducedIn = OGLIntroducedIn.V1P4; break; 252 case "1.5": fe.introducedIn = OGLIntroducedIn.V1P5; break; 253 case "2.0": fe.introducedIn = OGLIntroducedIn.V2P0; break; 254 case "2.1": fe.introducedIn = OGLIntroducedIn.V2P1; break; 255 case "3.0": fe.introducedIn = OGLIntroducedIn.V3P0; break; 256 case "3.1": fe.introducedIn = OGLIntroducedIn.V3P1; break; 257 case "3.2": fe.introducedIn = OGLIntroducedIn.V3P2; break; 258 case "3.3": fe.introducedIn = OGLIntroducedIn.V3P3; break; 259 case "4.0": fe.introducedIn = OGLIntroducedIn.V4P0; break; 260 case "4.1": fe.introducedIn = OGLIntroducedIn.V4P1; break; 261 case "4.2": fe.introducedIn = OGLIntroducedIn.V4P2; break; 262 case "4.3": fe.introducedIn = OGLIntroducedIn.V4P3; break; 263 case "4.4": fe.introducedIn = OGLIntroducedIn.V4P4; break; 264 case "4.5": fe.introducedIn = OGLIntroducedIn.V4P5; break; 265 default: break; 266 } 267 continue F8; 268 } 269 } 270 } 271 } 272 } 273 } 274 } 275 break; 276 277 case "extensions": 278 foreach(child2; child.childNodes) { 279 string extName = child2.attributes.getNamedItem("name").nodeValue; 280 281 foreach(child3; child2.childNodes) { 282 F9: foreach(child4; child3.childNodes) { 283 if (child4.nodeName == "command") { 284 string name = child4.attributes.getNamedItem("name").nodeValue; 285 foreach(ref fg; ret_Functions) { 286 foreach(ref fe; fg.functions) { 287 if (fe.name == name && fe.introducedInExtension is null) { 288 fe.introducedInExtension = extName; 289 continue F9; 290 } 291 } 292 } 293 } 294 } 295 } 296 } 297 break; 298 299 default: 300 break; 301 } 302 } 303 }